home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 015a / swap300.zip / SWAP.DOC < prev    next >
Text File  |  1990-10-04  |  64KB  |  1,690 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.                                   swap()
  13.  
  14.  
  15.                                Version 3.00
  16.                               October 4, 1990
  17.  
  18.  
  19.                             Copyright (C) 1990
  20.                            by Marty Del Vecchio
  21.  
  22.  
  23.  
  24.  
  25.  
  26.  
  27.  
  28.  
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41.  
  42.      This package (swap) includes an MS-DOS assembly-language routine that
  43.      can be called from a C program.  It will swap most of the current
  44.      program to extended memory (supplied by an XMS driver, such as
  45.      HIMEM.SYS), expanded memory (EMS version 4.0), or disk, thus freeing up
  46.      more memory for DOS.  It will then execute another program in its
  47.      place, and re-load the original program to its original state.  This
  48.      allows large DOS programs to execute other programs without the
  49.      original program taking up DOS memory.
  50.  
  51.  
  52.  
  53.  
  54.  
  55.                              Table of Contents
  56.  
  57.  
  58.      I.   Introduction . . . . . . . . . . . . . . . . . . .  1
  59.  
  60.      II.  File List  . . . . . . . . . . . . . . . . . . . .  2
  61.  
  62.      III. Functional Description . . . . . . . . . . . . . .  3
  63.           A.   DOS Memory Management . . . . . . . . . . . .  3
  64.           B.   How swap() Works  . . . . . . . . . . . . . .  4
  65.           C.   Swapping to Different Media . . . . . . . . .  6
  66.                1.   Extended Memory  . . . . . . . . . . . .  7
  67.                2.   Expanded Memory  . . . . . . . . . . . .  8
  68.                3.   DOS Disk File  . . . . . . . . . . . . .  9
  69.  
  70.      IV.  Calling the swap() Routine . . . . . . . . . . . . 11
  71.           A.   The swap() Return Code  . . . . . . . . . . . 11
  72.           B.   Program File to Execute . . . . . . . . . . . 12
  73.           C.   Program Command Line  . . . . . . . . . . . . 13
  74.           D.   EXEC Return Code Pointer  . . . . . . . . . . 13
  75.           E.   Swap File Name  . . . . . . . . . . . . . . . 15
  76.  
  77.      V.   Customizing swap() . . . . . . . . . . . . . . . . 16
  78.           A.   Memory Model  . . . . . . . . . . . . . . . . 16
  79.           B.   Swap Locations  . . . . . . . . . . . . . . . 17
  80.           C.   Swap Order  . . . . . . . . . . . . . . . . . 17
  81.           D.   Fragmentation . . . . . . . . . . . . . . . . 18
  82.  
  83.      VI.  Compiler-Specific Issues . . . . . . . . . . . . . 20
  84.           A.   Microsoft C 5.10  . . . . . . . . . . . . . . 20
  85.           B.   Microsoft C 6.00  . . . . . . . . . . . . . . 21
  86.           C.   Turbo C 2.0 . . . . . . . . . . . . . . . . . 21
  87.                1.   Command Line . . . . . . . . . . . . . . 21
  88.                2.   Integrated Environment . . . . . . . . . 23
  89.           D.   Turbo C++ 1.0 . . . . . . . . . . . . . . . . 23
  90.                1.   Command Line . . . . . . . . . . . . . . 23
  91.                2.   Integrated Environment . . . . . . . . . 24
  92.  
  93.      VII. Revision History . . . . . . . . . . . . . . . . . 26
  94.  
  95.      VIII. Information . . . . . . . . . . . . . . . . . . . 27
  96.  
  97.  
  98.  
  99.  
  100. I.   Introduction
  101.  
  102.      Most DOS programmers have figured out how to load and execute another
  103. DOS program from inside their own program (using the DOS EXEC system call). 
  104. Almost invariably, they discover a rather large problem:  with their
  105. original program loaded in memory, there is little memory left over in which
  106. to run the child program.  Often, there is not enough memory to run even a
  107. DOS shell.
  108.  
  109.      This package provides a solution to that problem.  The swap() routine
  110. will swap the original program to extended memory, expanded memory, or disk,
  111. then free up that memory.  It will then execute the DOS program specified by
  112. the caller.  When that program terminates, the original program is loaded
  113. back into memory, and it continues execution.
  114.  
  115.      By default, the swap() routine will attempt to swap the current program
  116. to extended memory; if that fails, it will try expanded memory; if that
  117. fails, it will try a DOS disk file.  By re-assembling the routine in
  118. (SWAP.ASM), the programmer can specify which combination of the above media
  119. to attempt to swap to, and in which order the swapping shall be attempted. 
  120. Details are provided in Chapter V.
  121.  
  122.      These routines have been tested with DOS versions 3.30 and 4.01.  They
  123. have been tested with Turbo C version 2.0, Turbo C++ version 1.0, Microsoft
  124. C version 5.10, and Microsoft C version 6.00.  Please see Chapter III, part
  125. B, for information about special problems with Microsoft C 6.00.
  126.  
  127.      All of these compilers comply with the Microsoft DOS standard segment
  128. naming and ordering convention (called DOSSEG in MASM).  If your C compiler
  129. does not support this convention, please contact me:  these routines should
  130. be adaptable to any compiler.
  131.  
  132.  
  133.  
  134.  
  135.  
  136.  
  137.  
  138.  
  139.  
  140.  
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149.  
  150.  
  151.  
  152.  
  153.  
  154. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          1
  155.  
  156.  
  157.  
  158.  
  159. II.  File List
  160.  
  161.      The following files should be found in this release:
  162.  
  163.      SWAP.DOC       This file.  Documentation for use of the swap() routine.
  164.      SWAP.ASM       The assembly-language source file for the swap()
  165.                     routines.  Requires the Microsoft Macro Assembler
  166.                     version 5.10 or the Turbo Assembler 1.0 (or above).
  167.      SWAP.H         Header file for SWAP.ASM.  Contains function prototypes
  168.                     and constant definitions needed to use swap().
  169.  
  170.      SWAPS.OBJ      swap() assembled (MASM 5.1) for Small memory model.
  171.      SWAPM.OBJ      swap() assembled (MASM 5.1) for Medium memory model.
  172.      SWAPC.OBJ      swap() assembled (MASM 5.1) for Compact memory model.
  173.      SWAPL.OBJ      swap() assembled (MASM 5.1) for Large memory model.
  174.  
  175.      SWAPTEST.C     Sample program (Microsoft C 6.00) demonstrating use and
  176.                     features of swap().
  177.      SWAPTEST.MSC   Make file (Microsoft MAKE.EXE) for creating SWAPTEST.EXE
  178.                     in the large memory model, using Microsoft C 6.00.
  179.      SWAPTEST.OBJ   SWAPTEST.C compiled with Microsoft C 6.00, Large memory
  180.                     model.
  181.      SWAPTEST.EXE   Sample program compiled in the large memory model with
  182.                     Microsoft C 6.00 (SWAPTEST.OBJ, SWAPL.OBJ).
  183.  
  184.      MSC.ZIP        Sample programs specific to Microsoft C compiler,
  185.                     version 5.10 and 6.00:
  186.                     SWAPTEST.C     Sample program source file
  187.                     SWAPTEST.MSC   Make file for SWAPTEST.EXE
  188.                                    (enter "make swaptest.msc")
  189.                     SWAP?.OBJ      SWAP.ASM assembled with MASM 5.1 for all
  190.                                    four memory models.
  191.  
  192.      TC2.ZIP        Sample programs specific to Turbo C, version 2.0:
  193.                     SWAPTEST.C     Sample program source file
  194.                     SWAPTEST.TC2   Make file for SWAPTEST.EXE
  195.                                    (enter "make -fswaptest.tc2")
  196.                     SWAP?.OBJ      SWAP.ASM assembled with TASM 1.0 for all
  197.                                    four memory models.
  198.  
  199.      TCP.ZIP        Sample programs specific to Turbo C++, version 1.0:
  200.                     SWAPTEST.C     Sample program source file
  201.                     SWAPTEST.TCP   Make file for SWAPTEST.EXE
  202.                                    (enter "make -fswaptest.tcp")
  203.                     SWAP?.OBJ      SWAP.ASM assembled with TASM 1.0 for all
  204.                                    four memory models.
  205.  
  206.      WHATS.NEW      A short text file describing features added in this
  207.                     version of swap().
  208.  
  209.  
  210.  
  211.  
  212.  
  213. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          2
  214.  
  215.  
  216.  
  217.  
  218. III. Functional Description
  219.  
  220.  
  221. A.  DOS Memory Management
  222.  
  223.      The functionality of swap() depends on the simplicity and
  224. predictability of the DOS memory management system.  The same system that
  225. was introduced in DOS version 1.0 in 1981 is still in use in DOS 4.01,
  226. released in 1989.
  227.  
  228.      Basically, DOS has 640K of memory to manage:  the hex addresses from
  229. 0000 to 9FFF (understanding DOS segments is not a requirement of this
  230. package!).  Once DOS is loaded, there is one large block of free memory.  In
  231. front of this block is a 16-byte header called a Memory Control Block (MCB),
  232. which contains information about the block such as how large it is.
  233.  
  234.      Whenever a DOS program is loaded and executed, DOS allocates part of
  235. this block of memory and assigns it to the program.  The program's block of
  236. memory gets its own MCB, and the remaining memory gets another MCB.  DOS
  237. functions 48 hex (allocate memory block), 49 hex (free memory block), and 4A
  238. hex (change size of memory block) all affect the chain of memory blocks
  239. maintained by DOS.
  240.  
  241.      Here is a map of what happens when FATHER.EXE, a mythical example
  242. program, is loaded into DOS and then executes a child program (CHILD.EXE):
  243.  
  244.  Before executing CHILD         Address        While executing CHILD
  245. +------------------------+       0000        +------------------------+
  246. +                        +                    +                       +
  247. +    Used by DOS, TSRs   +                   +    Used by DOS, TSRs   +
  248. +------------------------+       2000        +------------------------+
  249. +                        +                   +                        +
  250. +    FATHER.EXE, the     +                   +      FATHER.EXE        +
  251. +    current program     +                   +                        +
  252. +------------------------+       4000        +------------------------+
  253. +                        +                   +                        +
  254. +    DOS Free Memory     +                   +    CHILD.EXE, the      +
  255. +                        +                   +    current program     +
  256. +                        +                   +                        +
  257. +                        +       6000        +                        +
  258. +                        +                   +                        +
  259. +                        +                   +                        +
  260. +                        +                   +                        +
  261. +                        +                   +                        +
  262. +                        +                   +------------------------+
  263. +                        +                   +                        +
  264. +                        +                   +    DOS Free Memory     +
  265. +                        +                   +                        +
  266. +                        +                   +                        +
  267. +------------------------+       9FFF        +------------------------+
  268.  
  269.  
  270.  
  271.  
  272. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          3
  273.  
  274.  
  275.  
  276.  
  277.  
  278.      As you can see, when CHILD.EXE is executed, DOS splits up the large
  279. "DOS Free Memory" block into two smaller blocks--one used by CHILD, and the
  280. other still marked as free.  And notice that while CHILD is running, FATHER
  281. is still occupying a large block of DOS memory.  This puts a limit on the
  282. amount of memory available to CHILD.
  283.  
  284.      In this picture, since there is free memory immediately after CHILD,
  285. CHILD can call DOS system function 4A hex to increase the size of its memory
  286. block.  A program can always decrease the size of its memory block, as long
  287. as it no longer accesses information outside of its block.  And finally, a
  288. program can call DOS system function 48 hex to allocate a new block of
  289. memory, if any DOS free memory exists.
  290.  
  291.  
  292. B.   How swap() Works
  293.  
  294.      As stated above, DOS memory management is very predictable.  The swap()
  295. routine takes advantage of this predictability in the following manner. 
  296. Assume that the FATHER.EXE program above uses swap() to execute CHILD.EXE.
  297.  
  298.      1)   swap() takes the contents of the memory block that FATHER occupies
  299.           and saves it outside of DOS memory (to extended memory, expanded
  300.           memory, or disk).  In addition, swap() saves the contents of
  301.           whatever other DOS memory blocks FATHER owns.
  302.  
  303.      2)   swap() calls DOS system function 4A hex to shrink the size of
  304.           FATHER's memory block.  It makes this block as small as possible
  305.           while still keeping the swap() routine in memory.
  306.  
  307.      3)   swap() calls DOS system function 4B hex to execute the CHILD.EXE
  308.           program (as specified by the caller).
  309.  
  310.      4)   When CHILD.EXE terminates, swap() again calls DOS system function
  311.           4A hex, this time to restore FATHER's block to the same size it
  312.           was before swap() was called.  In addition, swap() calls DOS
  313.           function 48 hex to re-allocate the extra DOS memory blocks that
  314.           FATHER owned.
  315.  
  316.      5)   Finally, swap() retrieves the original contents of FATHER's memory
  317.           blocks (saved in step 1) and restores the FATHER.EXE program to
  318.           its original state.
  319.  
  320.      The key here is step 4.  We assume that the CHILD program is not a
  321. Terminate and Stay Resident (TSR) program, and that when it terminates, the
  322. memory it occupied is again free.  If this is the case, the DOS function 4A
  323. hex will predictably let us grow our memory block back to its original size,
  324. and DOS function 48 hex will predictably let us re-allocate whatever extra
  325. DOS memory blocks FATHER had allocated.
  326.  
  327.  
  328.  
  329.  
  330.  
  331. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          4
  332.  
  333.  
  334.  
  335.  
  336.      Following are maps of what happens in the above process:
  337.  
  338.   Before FATHER       While CHILD is      After CHILD ends
  339.   executes CHILD      executing           and FATHER is restored
  340. +-------------------+-------------------+-------------------+    0000
  341. +  DOS, TSRs, etc.  +  DOS, TSRs, etc.  +  DOS, TSRs, etc.  +
  342. +-------------------+-------------------+-------------------+    2000
  343. +    FATHER.EXE     + FATHER (swap code)+    FATHER.EXE     +
  344. +    (original      +-------------------+    (restored      +    3000
  345. +      size)        +                   +    to original    +
  346. +                   +     CHILD.EXE     +       size)       +
  347. +                   +                   +                   +
  348. +                   +                   +                   +
  349. +-------------------+                   +-------------------+    6000
  350. +                   +                   +                   +
  351. + DOS Free Memory   +                   + DOS Free Memory   +
  352. +                   +                   +                   +
  353. +                   +-------------------+                   +
  354. +                   +                   +                   +
  355. +                   + DOS Free Memory   +                   +
  356. +                   +                   +                   +
  357. +                   +                   +                   +
  358. +                   +                   +                   +
  359. +                   +                   +                   +
  360. +                   +                   +                   +
  361. +                   +                   +                   +
  362. +-------------------+-------------------+-------------------+
  363.  
  364.      There are several restrictions on use of the swap() routine, but the
  365. bottom line is that swap() lets you free all but about 2 kilobytes
  366. (depending on compiler, memory model, and swap() features) of your program's
  367. memory for use by another program.  Guidelines for using swap() are
  368. described in Chapter IV.
  369.  
  370.      The swap() routine has been tested with and should work for all memory
  371. models with the following compilers:
  372.  
  373.      Turbo C 2.0
  374.      Turbo C++ 1.0
  375.      Microsoft C 5.10
  376.      Microsoft C 6.00
  377.  
  378.      With the exception of Microsoft C 6.00, the above compilers all produce
  379. DOS executable programs that use only one DOS memory allocation block. 
  380. Whenever the program needs more memory (for dynamic memory allocation, for
  381. example), the C library routines call DOS function 4A hex to expand the size
  382. of its block.
  383.  
  384.      With Microsoft C version 6.00, however, things are not always as
  385. simple.  For the Small and Medium memory models, the above rule applies. 
  386. But for the Compact and Large memory models (with multiple data segments),
  387. Microsoft C 6.00 allocates extra DOS memory blocks with DOS function 48 hex. 
  388.  
  389.  
  390. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          5
  391.  
  392.  
  393.  
  394.  
  395. These extra blocks are used for such things as holding a copy of the
  396. environment, the far heap (fmalloc()), and a buffer for printf.  In
  397. addition, if your program directly allocates DOS memory blocks
  398. (_dos_allocmem() in Microsoft C, allocmem() in Turbo C), you will face the
  399. same problem.
  400.  
  401.      Starting with version 3.00, swap() will handle this type of DOS memory
  402. fragmentation, and will provide maximum available memory for the executed
  403. program.  The swap() routine accomplishes this by saving the contents of
  404. these extra blocks, then using DOS function 49 hex to free them.  When the
  405. child program is loaded and executed, all these free blocks are combined
  406. into one large block.  When the child program terminates, swap() resizes the
  407. main program block as usual, then re-allocates these extra blocks with DOS
  408. function 48 hex.  The swap() routine then restores the contents of these
  409. blocks.
  410.  
  411.      Under almost all circumstances, this process works smoothly and
  412. reliably (again due to the predictability of the DOS memory management
  413. strategies).  However, under some circumstances, this procedure can fail,
  414. and the program cannot be re-loaded successfully.  When swap() allocates the
  415. blocks after the execution of the child program, the address returned by DOS
  416. must match EXACTLY the original address of the block.  In most cases, this
  417. occurs, and everything is fine.  However, if for some reason DOS returns a
  418. different address, the program restore fails.
  419.  
  420.      As stated above, this is rare, but it can happen.  About the only way
  421. to force this to happen is to load several Terminate-and-Stay-Resident (TSR)
  422. programs, and then unload the first one, leaving a hole in the DOS memory
  423. chain.  When swap() calls DOS to allocate a block after the swap, DOS may
  424. see this hole and use it, instead of using the original address.  In this
  425. case, the program cannot be reloaded.  
  426.  
  427.      To reiterate:  if you use Microsoft C 6.00 (Compact or Large model), or
  428. if your program allocates extra DOS memory blocks, then you need this
  429. fragmentation feature of swap().  There is an extra risk of your program not
  430. being re-loaded after execution of the child program, but this risk is very
  431. small.  As usual, it is up to you to decide whether to use this feature or
  432. not.  See Chapter V, Section D for details on how to enable and disable this
  433. feature.
  434.  
  435.  
  436. C.   Swapping to Different Media
  437.  
  438.      The swap() routine can be configured to swap your program to extended
  439. memory, expanded memory, or disk.  This behavior can be customized, as
  440. discussed in Chapter V.  This section details how swap() deals with each
  441. media.
  442.  
  443.  
  444.  
  445.  
  446.  
  447.  
  448.  
  449. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          6
  450.  
  451.  
  452.  
  453.  
  454. 1.   Extended Memory
  455.  
  456.      Extended memory is a term used to describe memory available on 80286-
  457. and 80386-based personal computers that is not DOS memory.  On such a PC,
  458. the first megabyte of memory (0K to 1024K) is used for DOS memory, system
  459. BIOS, adapter BIOS and memory, etc.  Memory above 1024K is called extended
  460. memory.  It is generally not used by DOS, which is designed to run on the
  461. 8086 processor, which can only address the first 1024K of memory.
  462.  
  463.      Until recently, there had been no standard way of allocating,
  464. addressing, and using this memory.  Access to extended memory depended to
  465. some extent on a vendor's hardware design and BIOS implementation.  The main
  466. problem was ownership of this memory--there was no standard way that one
  467. program (such as a disk cache) could tell another program that it owned a
  468. block of extended memory.
  469.  
  470.      Recently, however, the eXtended Memory Specification (XMS) was released
  471. by Microsoft and other companies.  The XMS spec described a driver that
  472. controlled all of extended memory, and defined a programming interface to
  473. that driver that applications could use to allocate, use, and free extended
  474. memory.  Microsoft ships such a driver (called HIMEM.SYS) with its Windows
  475. programs, and it is generally available on bulletin boards.
  476.  
  477.      In order for swap() to use extended memory, HIMEM.SYS (or an
  478. equivalent) must be loaded.  If a system has extended memory, but is not
  479. running HIMEM.SYS, swap() will not be able to see the memory, and cannot use
  480. it.
  481.  
  482.      When swap() tries to use XMS extended memory, it first checks to see if
  483. HIMEM.SYS (or an equivalent) is loaded.  It does this by calling the
  484. multiplex interrupt (2F hex) with 4300 hex in AX.  If HIMEM.SYS is loaded,
  485. it returns 80 hex in AL.
  486.  
  487.      Once swap() confirms that HIMEM.SYS is loaded, it calculates how much
  488. extended memory it needs, and calls XMS function 09, allocate extended
  489. memory block.  If this call fails (there is not enough extended memory
  490. free), the swap to extended memory fails.  If the allocate call succeeds,
  491. swap() will call XMS function 0B hex, move extended memory block.  It sets
  492. up a request packet to copy the contents of the current program's DOS memory
  493. block (and the contents of that program's extra DOS blocks, if any) into the
  494. extended memory block it has just allocated.
  495.  
  496.      The swap() routine will then shrink its program's DOS memory block (and
  497. free its extra DOS blocks), call the DOS EXEC function to execute the
  498. requested program, and restore the DOS memory block to its original size
  499. (and re-allocate the extra DOS blocks).  Details on this are found in
  500. Chapter III, Section A.
  501.  
  502.      Once the executed program terminates, swap() again calls XMS function
  503. 0B hex to copy the contents of the program from extended memory back into
  504. the DOS memory blocks.  Finally, XMS function 0A hex is called to free the
  505. allocated extended memory, and swap() returns to the caller.
  506.  
  507.  
  508. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          7
  509.  
  510.  
  511.  
  512.  
  513.  
  514.      At this point, the original program resides in DOS memory just as it
  515. did before the call to swap(), and swap() has completely cleaned up its
  516. usage of XMS extended memory.
  517.  
  518.  
  519. 2.   Expanded Memory
  520.  
  521.      Expanded memory is a special kind of memory that can be added to any
  522. PC, but that does not exist in the processor's address space.  Lotus, Intel,
  523. and Microsoft (LIM) defined a specification of how to provide expanded
  524. memory in a PC and how to access it from an application program.  The
  525. original specification was called LIM EMS 3.2, and it was updated to version
  526. 4.0 later.  
  527.  
  528. NOTE:     Previous versions of swap() (2.11 and before) were able to use EMS
  529.           version 3.2 or EMS version 4.0.  Due to the extra complications
  530.           encountered with Microsoft C 6.00 and multiple DOS memory blocks,
  531.           swap() version 3.00 and later cannot use EMS version 3.2.  This
  532.           version of swap() must have EMS version 4.0 in order to swap to
  533.           expanded memory.
  534.  
  535.           If you have an expanded memory board (such as the Intel Above
  536.           Board or the AST Rampage Plus), and your EMS driver only supports
  537.           EMS version 3.2, please contact your card's manufacturer for an
  538.           updated EMS driver.  Almost every manufacturer has upgraded its
  539.           software by now to support EMS 4.0.
  540.  
  541.      Expanded memory is provided in a system in 16-kilobyte (16K) blocks
  542. called pages.  An application can allocate and free any number of pages in
  543. units referred to by handles.  When the application wants to copy data to or
  544. from a page, it can either ask the EMS driver to map that page into the PC's
  545. address space and do a memory copy, or it can use EMS 4.0 function 57 hex to
  546. perform the memory copy.  Swap() version 3.00 and later use this latter
  547. method of transferring data to and from expanded memory, and thus must have
  548. an EMS 4.0 driver.
  549.  
  550.      When swap() tries to use EMS memory, it first checks to see if an EMS
  551. driver is loaded.  It does this by looking at interrupt vector 67 hex.  The
  552. string "EMM0XXXX" should be found 13 bytes after that vector address.  If it
  553. is, an EMS driver is loaded.
  554.  
  555.      Once swap() confirms that an EMS driver is loaded, it calculates how
  556. many 16K expanded memory pages it needs, and calls EMS function 43 hex,
  557. "allocate expanded memory pages."  If this call fails (there is not enough
  558. expanded memory free), the swap to expanded memory fails.
  559.  
  560.      If this call succeeds, swap() will copy the contents of the current
  561. program memory block (and its extra DOS blocks) to the expanded memory using
  562. EMS 4.0 function 57 hex, "move memory region".  The EMS driver will perform
  563. the actual transfer of data from DOS memory to expanded memory.
  564.  
  565.  
  566.  
  567. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          8
  568.  
  569.  
  570.  
  571.  
  572.      The swap() routine will then shrink its program's DOS memory block (and
  573. free its extra DOS blocks), call the DOS EXEC function to execute the
  574. requested program, and restore the DOS memory block to its original size
  575. (and re-allocate the extra DOS blocks).  Details on this are found in
  576. Chapter III, Section A.
  577.  
  578.      Once the executed program terminates, swap() again calls EMS function
  579. 57 hex to copy the data from expanded memory back to its original location. 
  580. Finally, EMS function 45 hex is called to free the allocated expanded
  581. memory, and swap() returns to the caller.
  582.  
  583.      At this point, the original program resides in DOS memory just as it
  584. did before the call to swap(), and swap() has completely cleaned up its
  585. usage of EMS expanded memory.
  586.  
  587.  
  588. 3.   DOS Disk File
  589.  
  590.      The swap() routine can also use the DOS file system to temporarily save
  591. the contents of a program.  Although swapping to a disk file is much slower
  592. than swapping to extended or expanded memory, it is just as effective.
  593.  
  594.      The name of the disk file to swap to is provided by the caller as a
  595. parameter (see Chapter IV).  The swap() routine will call DOS function 3C
  596. hex to create the file (or truncate it if it already exists).  The file will
  597. be hidden to provide a small amount of protection for the file.  If this
  598. create fails, the swap to disk fails.
  599.  
  600.      Once the file is created, the swap() routine follows a procedure
  601. similar to the one outlined above in the description for swapping to EMS. 
  602. The original program will be swapped in 32K blocks to the disk file, with
  603. the data being written with DOS function 40 hex.  If any call to this
  604. function fails, it most likely means that the disk is full.  If this
  605. happens, swap() will delete the file, and the swap to disk fails. 
  606. Otherwise, swap() will continue to write 32K blocks until the entire program
  607. is saved.
  608.  
  609.      The swap() routine will then shrink its program's DOS memory block (and
  610. free its extra DOS blocks), call the DOS EXEC function to execute the
  611. requested program, and restore the DOS memory block to its original size
  612. (and re-allocate the extra DOS blocks).  Details on this are found in
  613. Chapter III, Section A.
  614.  
  615.      When the executed program terminates, swap() will call DOS function 3D
  616. hex to open the swap file.  If the file is not there, swap() cannot restore
  617. the original program.  If this is the case, swap() will print an error
  618. message to the screen and terminate the program.
  619.  
  620.      If the file is there, swap() will simply read 32K chunks from the disk
  621. file into the DOS memory block using DOS function 3F hex.  It will do this
  622. until the entire contents of the original program are restored.  It will
  623. then call DOS function 41 hex to delete the swap file.
  624.  
  625.  
  626. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                          9
  627.  
  628.  
  629.  
  630.  
  631.  
  632.      At this point, the original program resides in DOS memory just as it
  633. did before the call to swap(), and swap() has completely cleaned up its
  634. usage of DOS file system.
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645.  
  646.  
  647.  
  648.  
  649.  
  650.  
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657.  
  658.  
  659.  
  660.  
  661.  
  662.  
  663.  
  664.  
  665.  
  666.  
  667.  
  668.  
  669.  
  670.  
  671.  
  672.  
  673.  
  674.  
  675.  
  676.  
  677.  
  678.  
  679.  
  680.  
  681.  
  682.  
  683.  
  684.  
  685. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         10
  686.  
  687.  
  688.  
  689.  
  690. IV.  Calling the swap() Routine
  691.  
  692.      The swap() routine is designed to be called in a C program.  This is
  693. the function prototype for swap():
  694.  
  695.      int swap (char *program_name, 
  696.                char *command_line, 
  697.                char *exec_return, 
  698.                char *swap_fname);
  699.  
  700.      For example, to execute a DOS command shell and display a directory of
  701. the C: drive, you would call swap() this way:
  702.  
  703. swap_ret = swap ("C:\\COMMAND.COM", "/C dir c:", &exec_ret, "swap.fil");
  704.  
  705.      When building a program with swap(), you should put the swap() object
  706. module as early in the linker list as possible.  See Chapter VI for detailed
  707. information on using swap() with various compiler versions.
  708.  
  709.      The swap() routine also returns an int return code to the caller. 
  710. Following are descriptions for this return code and each of these
  711. parameters.
  712.  
  713.  
  714. A.   The swap() Return Code
  715.  
  716.      The swap() function returns an integer signifying the success or
  717. failure of the swap and execute.  There are four possible return codes,
  718. defined in SWAP.H and here:
  719.  
  720. 0:   SWAP_OK             Success--current program swapped, new program
  721.                          executed, and original program restored.
  722. 1:   SWAP_NO_SHRINK      Unable to shrink DOS memory block size.  This
  723.                          indicates an error in the DOS Memory Control Block
  724.                          chain.  This is unlikely.
  725. 2:   SWAP_NO_SAVE        Unable to save the program to any one of extended
  726.                          memory, expanded memory, or disk (depending on
  727.                          which functions were assembled).  The new program
  728.                          was not executed.
  729. 3:   SWAP_NO_EXEC        Unable to execute the new program.  If swap()
  730.                          returns this code, the parameter exec_return (see
  731.                          below) contains the DOS error code.
  732.  
  733.      In addition to these return codes, there is another type of error that
  734. can occur in swap() that cannot be returned to the caller.  If swap() is
  735. unable to restore the original program after calling the DOS EXEC function,
  736. it cannot return to the caller, because the caller no longer exists in DOS
  737. memory!
  738.  
  739.      This error can occur for various reasons.  If the program was swapped
  740. to disk, and the disk file was erased by the executed program, swap() has
  741.  
  742.  
  743.  
  744. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         11
  745.  
  746.  
  747.  
  748.  
  749. nothing to restore.  In addition, errors encountered in the XMS or EMS
  750. driver can cause this.
  751.  
  752.      If this happens, swap() takes the only recourse it can.  It prints the
  753. following message to the screen (the standard error location):
  754.  
  755.      SWAP:  Unable to restore program.
  756.  
  757. It then calls the DOS terminate function (4C hex) and returns 255 (FF hex)
  758. as the return code.  This code can be queried using the DOS ERRORLEVEL
  759. function.  For example, take this batch file:
  760.  
  761. Echo About to execute program that demonstrates swap():
  762. swaptest
  763. if errorlevel 255 echo ERROR--swap() was unable to restore program!
  764.  
  765.  
  766. B.   Program File to Execute
  767.  
  768.      The first parameter, program_name, is a pointer to a null-terminated
  769. string that contains the full path and file name of the program to be
  770. executed.  For example, if you wanted to execute a program called TEST.EXE
  771. which is located in C:\UTIL, you must call swap() this way:
  772.  
  773. swap_ret = swap ("C:\\UTIL\\TEST.EXE", "", &exec_ret, "swap.fil");
  774.  
  775.      The swap() routine will NOT perform any of the following functions:
  776.  
  777.      --   Search the DOS PATH environment variable for a program to execute
  778.      --   Redirect input or output with "<" or ">"
  779.      --   Execute a batch file
  780.  
  781. These functions cannot be performed by swap() because they are functions of
  782. the DOS command processor (COMMAND.COM), and not of the DOS EXEC function
  783. that swap() uses.  In order to do any of these things, you must explicitly
  784. invoke the command processor with the "/C" parameter, which tells
  785. COMMAND.COM to execute the following command.  For example, to execute a DIR
  786. command and redirect the output to "DIR.OUT", you would call swap() this
  787. way:
  788.  
  789. char *comspec;
  790. comspec = getenv ("COMSPEC");
  791. swap_ret = swap (comspec, "/C dir >dir.out", &exec_ret, "swap.fil");
  792.  
  793.      The getenv() function is available in Turbo C and Microsoft C to search
  794. the current environment for a string.  We use it here to determine where the
  795. DOS command processor is.
  796.  
  797.      When passing the program name parameter to swap(), remember that the
  798. "\" character, used by DOS as a directory and file name separator, is used
  799. by C to indicate an escape character.  Thus, to specify the file
  800. C:\UTIL\TEST.EXE, you must pass it as "C:\\UTIL\\TEST.EXE".
  801.  
  802.  
  803. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         12
  804.  
  805.  
  806.  
  807.  
  808.  
  809.      The program to be executed MUST NOT be a Terminate and Stay Resident
  810. (TSR) program.  If it is, swap() will not be able to grow the original
  811. program's DOS memory block back to its original size, and thus the original
  812. program cannot be re-loaded.
  813.  
  814.      Finally, remember that the name of the program file to be executed can
  815. be up to 127 characters (not including the null byte) long.  It is the
  816. responsibility of the caller to ensure that the file name is not longer than
  817. 127 characters.
  818.  
  819.  
  820. C.   Program Command Line
  821.  
  822.      The second parameter passed to swap() is the command line for the
  823. program to be run.  It is a pointer to a null-terminated string that can be
  824. between 0 and 127 characters (not including the null byte).  This string
  825. should NOT include the name of the program to be executed--that should be
  826. passed as a separate parameter as described above.
  827.  
  828.      For example, to call PKZIP.EXE and have it store files in TEST.ZIP, you
  829. would call swap() this way:
  830.  
  831. swap_ret = swap ("C:\\UTIL\\PKZIP.EXE", "-r -P test.zip *.*",
  832.                  &exec_ret, "swap.fil");
  833.  
  834.      It is the responsibility of the caller to ensure that the command line
  835. parameter string is not longer than 127 characters.
  836.  
  837.      In version 2.10 of swap(), code was added to parse the command line
  838. into two File Control Blocks (FCBs), which are then passed to the executed
  839. program.  This more closely emulates the way COMMAND.COM loads and executes
  840. a program.  This behavior has no effect on the contents of the command line.
  841.  
  842.      This code was added because some programs (such as DOS' CHKDSK.COM)
  843. assume that the first two command-line parameters will be parsed into the
  844. FCBs, and they use them.  If you tried to execute CHKDSK.COM with a version
  845. of swap() earlier than 2.10, CHKDSK would report "invalid drive".  This is
  846. because the command line parameter had not been parsed into the FCB.
  847.  
  848.      Code to parse the command line parameters into default FCBs was written
  849. and generously provided by David E. Jenkins.
  850.  
  851.  
  852. D.   EXEC Return Code Pointer
  853.  
  854.      The exec_return is a pointer to a char (8-bit value) where swap() will
  855. return information from the DOS EXEC function.  What is stored in this
  856. location depends on whether the swap() routine was successful or not.
  857.  
  858.      If swap() is successful (and returns 0, SWAP_OK described above),
  859. exec_return contains the return code of the executed program.  This is the
  860.  
  861.  
  862. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         13
  863.  
  864.  
  865.  
  866.  
  867. same value used in the DOS ERRORLEVEL comparison.  For example, if you
  868. execute PKUNZIP.EXE, and it gives the return code 0, meaning success, the
  869. byte pointed to by exec_return will be set to 0 by swap().
  870.  
  871.      If swap() is unsuccessful when trying to execute the new program (and
  872. returns 3, SWAP_NO_EXEC), swap() will place the DOS error code returned by
  873. EXEC in this value.  According to the DOS technical reference manual, this
  874. code will be one of the following (as defined in SWAP.H):
  875.  
  876. 0x01: BAD_FUNC           Bad DOS function number--unlikely
  877. 0x02: FILE_NOT_FOUND     File not found--couldn't find program_name
  878. 0x05: ACCESS_DENIED      Access denied--couldn't open program_name 
  879. 0x08: NO_MEMORY          Insufficient memory to run program_name
  880. 0x0A: BAD_ENVIRON        Invalid environment segment--unlikely  
  881. 0x0B: BAD_FORMAT         Format invalid--unlikely
  882.  
  883.      Here is an example of how to handle error codes:
  884.  
  885. char swap_ret, exec_ret;
  886.  
  887. swap_ret = swap ("C:\\UTIL\\PKUNZIP.EXE", "D:TEST.ZIP",
  888.                  &exec_ret, "swap.fil");
  889.  
  890. switch (swap_ret)
  891.    {
  892.    case SWAP_OK:         printf ("Successful, program returned %d.",
  893.                                  (int)exec_ret);
  894.                          break;
  895.    case SWAP_NO_SHRINK:  printf ("Unable to shrink DOS memory block.");
  896.                          break;
  897.    case SWAP_NO_SAVE:    printf ("Unable to save program.");
  898.                          break;
  899.    case SWAP_NO_EXEC:    printf ("EXEC call failed.  DOS error is: ");
  900.                          switch (exec_ret)
  901.                             {
  902.                             case BAD_FUNC:
  903.                                    printf ("Bad function.\n");   break;
  904.                             case FILE_NOT_FOUND:
  905.                                    printf ("File not found.\n"); break;
  906.                             case ACCESS_DENIED:
  907.                                    printf ("Access denied.\n");  break;
  908.                             case NO_MEMORY:
  909.                                    printf ("Insufficient memory.\n"); break;
  910.                             case BAD_ENVIRON:
  911.                                    printf ("Bad environment.\n"); break;
  912.                             case BAD_FORMAT:
  913.                                    printf ("Bad format.\n");      break;
  914.                             }
  915.                          break;
  916.    }
  917.  
  918.  
  919.  
  920.  
  921. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         14
  922.  
  923.  
  924.  
  925.  
  926. E.   Swap File Name
  927.  
  928.      The final parameter, swap_fname, is a pointer to a null-terminated
  929. string that contains the name of a DOS file to swap the program to.  This is
  930. only needed if the version of swap() you are using will try to swap to disk
  931. (see Chapter V).  If your version of swap() does not swap to disk at all,
  932. you can pass the null string ("").  This parameter will only be used if
  933. swap() actually does try to swap to disk.
  934.  
  935.      This file name need not be a complete drive, directory, and path name. 
  936. If the drive is not specified, it will be placed on the current drive; if
  937. the directory is not specified, it will be placed in the current directory.
  938.  
  939.      It is up to the caller to choose a safe file name for swapping.  You
  940. should not choose the name of a file that already exists, as that file's
  941. contents will be lost when swap() truncates it.  Because of this, you should
  942. be very careful not to specify the same file name for two different programs
  943. that use swap().
  944.  
  945.      For example, if you have a program called A.EXE which uses swap to call
  946. program B.EXE, which uses swap() to call program C.EXE, you must choose
  947. different swap file names.  If you use the same name (such as
  948. "C:\\SWAP.FIL") for both, you will have a problem.  When A.EXE executes
  949. B.EXE, c:\swap.fil will be created, and will contain the contents of A.EXE. 
  950. When B.EXE executes C.EXE and swaps to c:\swap.fil, the original contents of
  951. the file will be erased and replaced with the contents of B.EXE.  When C.EXE
  952. terminates, c:\swap.fil will be read and deleted.  Then when B.EXE
  953. terminates, the swap() routine in A.EXE will not find c:\swap.fil, and
  954. cannot reload A.EXE.
  955.  
  956. Note:     Swap() is unable to swap a program to a file that is located on a
  957.           Novell Netware file server.  Swap() will work with most networks
  958.           (such as Microsoft LAN Manager, Network OS, etc.) that use the
  959.           standard Microsoft Redirector.  This is because swap() uses DOS
  960.           function 60 hex (somewhat undocumented) to generate a full drive,
  961.           path, and file name of the swap file.  Microsoft Redirector
  962.           networks are supported by this DOS function, but Novell Netware is
  963.           not.  However, swap() can always save the program to a file
  964.           located on a local disk, even if that PC is running Novell
  965.           Netware.
  966.  
  967.  
  968.  
  969.  
  970.  
  971.  
  972.  
  973.  
  974.  
  975.  
  976.  
  977.  
  978.  
  979.  
  980. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         15
  981.  
  982.  
  983.  
  984.  
  985. V.   Customizing swap()
  986.  
  987.  
  988.      As stated above, the default configuration for swap() is a Small memory
  989. model function that attempts to swap the main program block AND whatever
  990. extra DOS memory blocks the program has allocated, in the following order:
  991.  
  992.      1)   XMS extended memory
  993.      2)   EMS expanded memory
  994.      3)   DOS disk file
  995.  
  996. You can use the included source file (SWAP.ASM) and the Microsoft Macro
  997. Assembler (MASM) version 5.10 or the Turbo Assembler (TASM) version 1.0 or
  998. later to create a customized version of the swap() routine.  To assemble the
  999. default version of swap(), you would execute MASM this way:
  1000.  
  1001.      masm swap /mx;
  1002.  
  1003. If you are using TASM, you must instruct it to emulate MASM:
  1004.  
  1005.      tasm swap /mx /JMASM51;
  1006.  
  1007. This will create SWAP.OBJ.  You must include "/mx" on the MASM command line
  1008. to tell the assembler to maintain the case of all variables and functions
  1009. declared there.  This allows the C program to access these items.
  1010.  
  1011.      This chapter describes how to create a customized version of swap().
  1012.  
  1013.  
  1014. A.   Memory Model
  1015.  
  1016.      The swap() routine supports four different C memory models, as defined
  1017. by Microsoft C and Turbo C.  The memory model specifies the number of
  1018. segments for code and data, and therefore the size of a code or data
  1019. pointer.  These memory models are:
  1020.  
  1021.      Small     One code segment, one data segment
  1022.      Medium    Multiple code segments, one data segment
  1023.      Compact   One code segment, multiple data segments
  1024.      Large     Multiple code segments, multiple data segments
  1025.  
  1026.      The swap() source file (SWAP.ASM) can be configured to support any of
  1027. these memory models with a command-line parameter to MASM.  The parameter is
  1028. "/D" followed by one of the following definitions:
  1029.  
  1030.      _small         Small memory model
  1031.      _medium        Medium memory model
  1032.      _compact       Compact memory model
  1033.      _large         Large memory model
  1034.  
  1035.      Please note that these definitions have changed from earlier versions
  1036. of swap().  Earlier versions (2.01 and earlier) did not have the underscore
  1037.  
  1038.  
  1039. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         16
  1040.  
  1041.  
  1042.  
  1043.  
  1044. before the name.  This caused problems with Turbo Assembler, which uses
  1045. those definitions for other purposes.  With these new definitions, you can
  1046. use Turbo Assembler to assemble SWAP.ASM.  To do this, you must tell TASM to
  1047. emulate the Microsoft Assembler (with /JMASM51, as described above).
  1048.  
  1049.      For example, to create a Large-model version of swap() with TASM, you
  1050. would assemble SWAP.ASM this way:
  1051.  
  1052.      tasm swap /D_Large /JMASM51;
  1053.  
  1054. This will create SWAP.OBJ that supports the Large memory model.  Case does
  1055. not matter when specifying the memory model.  If no model is specified, the
  1056. Small model is assumed.
  1057.  
  1058.      In addition to the above memory models, the Huge model should also be
  1059. supported by assembling swap() for the Large model.  I have done cursory
  1060. tests for this case, but success is by no means guaranteed.
  1061.  
  1062.  
  1063. B.   Swap Locations
  1064.  
  1065.      The swap() routine will swap a program to extended memory, expanded
  1066. memory, or disk file.  If you do not want swap() to swap to all of these
  1067. locations, you can re-assemble a custom version.  However, it is more
  1068. flexible to allow swap() to try all three locations, and the extra code
  1069. needed is minimal (about 1700 bytes total).
  1070.  
  1071.      This is also accomplished with the "/D" switch to MASM, followed by one
  1072. of the following:  "xms" for extended memory, "ems" for expanded memory, and
  1073. "disk" for disk file.  For example, to assemble a version of swap() that
  1074. only attempts to swap to extended memory, you would say:
  1075.  
  1076.      masm swap /Dxms;
  1077.  
  1078. To assemble a version of swap() that attempts to swap to extended or
  1079. expanded memory, you would say:
  1080.  
  1081.      masm swap /Dxms /Dems;
  1082.  
  1083.  
  1084. C.   Swap Order
  1085.  
  1086.      By default, swap() attempts to swap the original program to extended
  1087. memory;  if that fails, to expanded memory;  and if that fails, to disk. 
  1088. Naturally, it will only try each location if that location was specified
  1089. during assembly of SWAP.ASM (see Section B above).
  1090.  
  1091.      If you want to change the order in which swap() attempts to save the
  1092. program, you must change the source file SWAP.ASM manually.  Towards the end
  1093. of the file, there is a routine called save_program.  It contains three
  1094. blocks of code:
  1095.  
  1096.  
  1097.  
  1098. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         17
  1099.  
  1100.  
  1101.  
  1102.  
  1103. ; ********************************************************************
  1104. IFDEF USE_XMS
  1105. IF1
  1106.    %out -- XMS extended memory
  1107. ENDIF
  1108.                 call    save_xms  ; Try saving to XMS extended memory
  1109.                 jnc     save_ok   ; Carry clear == success, all done
  1110. ENDIF
  1111. ; ********************************************************************
  1112.  
  1113.  
  1114. ; ********************************************************************
  1115. IFDEF USE_EMS
  1116. IF1
  1117.    %out -- EMS expanded memory
  1118. ENDIF
  1119.                 call    save_ems  ; Try saving to EMS expanded memory
  1120.                 jnc     save_ok   ; Carry clear == success, all done
  1121. ENDIF
  1122. ; ********************************************************************
  1123.  
  1124.  
  1125. ; ********************************************************************
  1126. IFDEF USE_DISK
  1127. IF1
  1128.    %out -- DOS disk file
  1129. ENDIF
  1130.                 call    save_disk ; Try saving to DOS disk file
  1131.                 jnc     save_ok   ; Carry clear == success, all done
  1132. ENDIF
  1133. ; ********************************************************************
  1134.  
  1135.      These blocks are separated by lines of asterisks.  If you wanted swap()
  1136. to try expanded memory, then extended memory, then disk, you would move the
  1137. middle block (IFDEF USE_EMS to ENDIF) before the middle block.  This is
  1138. easily accomplished with most text editors.  
  1139.  
  1140.  
  1141. D.   Fragmentation
  1142.  
  1143.      Starting with swap() version 3.00, fragmented DOS memory allocation is
  1144. handled.  See Chapter III, Section D for information on this problem.
  1145.  
  1146.      By default, swap() supports swapping of multiple DOS blocks.  If you
  1147. want to disable this feature, you must add the parameter NoFrag to your MASM
  1148. or TASM command line.  For example, to disable fragmentation support when
  1149. building a large-model version of swap(), you would enter:
  1150.  
  1151.      tasm /D_Large /JMASM51 /mx /DNoFrag swap.asm, swapl.obj;
  1152.  
  1153.      Although disabling this feature saves some memory, the amount saved
  1154. (less than 100 bytes) is not really worth the price of possible memory
  1155.  
  1156.  
  1157. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         18
  1158.  
  1159.  
  1160.  
  1161.  
  1162. shortages.  However, the option is included to allow the programmer complete
  1163. control over the swap() routine.
  1164.  
  1165.  
  1166.  
  1167.  
  1168.  
  1169.  
  1170.  
  1171.  
  1172.  
  1173.  
  1174.  
  1175.  
  1176.  
  1177.  
  1178.  
  1179.  
  1180.  
  1181.  
  1182.  
  1183.  
  1184.  
  1185.  
  1186.  
  1187.  
  1188.  
  1189.  
  1190.  
  1191.  
  1192.  
  1193.  
  1194.  
  1195.  
  1196.  
  1197.  
  1198.  
  1199.  
  1200.  
  1201.  
  1202.  
  1203.  
  1204.  
  1205.  
  1206.  
  1207.  
  1208.  
  1209.  
  1210.  
  1211.  
  1212.  
  1213.  
  1214.  
  1215.  
  1216. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         19
  1217.  
  1218.  
  1219.  
  1220.  
  1221. VI.  Compiler-Specific Issues
  1222.  
  1223.      The source file for the swap() routine, SWAP.ASM, supports the four
  1224. major memory models (Small, Medium, Compact, and Large) of the following
  1225. compilers:
  1226.  
  1227.      Microsoft C 5.10
  1228.      Microsoft C 6.00
  1229.      Turbo C 2.0
  1230.      Turbo C++ 1.0
  1231.  
  1232.      This chapter provides information on optimizing swap() for use with
  1233. each memory model of each compiler.
  1234.  
  1235.      The basic guideline for linking swap() into your executable is this: 
  1236. link the swap() object module (SWAPS.OBJ, etc.) into your executable as
  1237. early as possible.  Swap() can only swap out the modules that follow it in
  1238. the executable, so putting it as early as possible allows for maximum memory
  1239. for the executed program.  The following sections provide specific
  1240. information for each compiler.
  1241.  
  1242.  
  1243. A.   Microsoft C 5.10
  1244.  
  1245.      The file MSC.ZIP, included in this distribution, contains example files
  1246. for building SWAPTEST.EXE with Microsoft C 5.10 and 6.00 (using MASM 5.10). 
  1247. A make file called SWAPTEST.MSC is included that automates the process of
  1248. building SWAPTEST.EXE.  To make SWAPTEST.EXE, enter the following at the DOS
  1249. command prompt:
  1250.  
  1251.      make swaptest.msc
  1252.  
  1253. Following is a list of issues with Microsoft C 5.10:
  1254.  
  1255.      1.   Make sure the .CODE declaration in SWAP.ASM looks like this:
  1256.  
  1257.           IF @codesize
  1258.           .CODE   SWAP_TEXT
  1259.           ELSE
  1260.           .CODE
  1261.           ENDIF
  1262.  
  1263.      2.   Make sure the object file that contains swap() is listed as the
  1264.           first object file when linking your executable:
  1265.  
  1266.           link $(LINKDEFS) swapl + swaptest, swaptest, swaptest;
  1267.  
  1268.           This ensures that your executable will take up as little memory as
  1269.           possible when it is executing a child program using swap().
  1270.  
  1271.      3.   Unless your program directly allocates extra DOS memory blocks
  1272.           (either by calling DOS function 48 hex or by calling
  1273.  
  1274.  
  1275. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         20
  1276.  
  1277.  
  1278.  
  1279.  
  1280.           _dos_allocmem()), you can get by without using the fragmentation
  1281.           feature of swap() ("/DNoFrag").  However, the memory savings will
  1282.           be minimal, and this is not recommended.
  1283.  
  1284.  
  1285. B.   Microsoft C 6.00
  1286.  
  1287.      The file MSC.ZIP, included in this distribution, contains example files
  1288. for building SWAPTEST.EXE with Microsoft C 5.10 and 6.00 (using MASM 5.10). 
  1289. A make file called SWAPTEST.MSC is included that automates the process of
  1290. building SWAPTEST.EXE.  To make SWAPTEST.EXE, enter the following at the DOS
  1291. command prompt:
  1292.  
  1293.      make swaptest.msc
  1294.  
  1295. Following is a list of issues with Microsoft C 6.00:
  1296.  
  1297.      1.   Make sure the .CODE declaration in SWAP.ASM looks like this:
  1298.  
  1299.           IF @codesize
  1300.           .CODE   SWAP_TEXT
  1301.           ELSE
  1302.           .CODE
  1303.           ENDIF
  1304.  
  1305.      2.   Make sure the object file that contains swap() is listed as the
  1306.           first object file when linking your executable:
  1307.  
  1308.           link $(LINKDEFS) swapl + swaptest, swaptest, swaptest;
  1309.  
  1310.           This ensures that your executable will take up as little memory as
  1311.           possible when it is executing a child program using swap().
  1312.  
  1313.      3.   If you are using the Compact or Large memory model, you must use
  1314.           the fragmentation feature of swap() in order to provide maximum
  1315.           memory for the executed program.  If you specify "/DNoFrag" on the
  1316.           MASM command line, you disable this feature, and your child
  1317.           program will not have as much memory as it could.
  1318.  
  1319.  
  1320. C.   Turbo C 2.0
  1321.  
  1322.      Turbo C 2.0 provides two ways to build an executable program:  a
  1323. command-line environment (using TCC.EXE and TLINK.EXE), and an integrated
  1324. development environment.
  1325.  
  1326.      The file TC2.ZIP, included in this distribution, contains example files
  1327. for building SWAPTEST.EXE with Turbo C 2.0, both command-line and integrated
  1328. environments.
  1329.  
  1330.  
  1331. 1.   Command Line
  1332.  
  1333.  
  1334. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         21
  1335.  
  1336.  
  1337.  
  1338.  
  1339.  
  1340.      You can build SWAPTEST.EXE with TCC.EXE (Turbo C 2.0), TASM.EXE (Turbo
  1341. Assembler 1.0), TLINK.EXE (Turbo Linker 2.0), and MAKE.EXE (Turbo Make 2.0). 
  1342. A make file called SWAPTEST.TC2 is included to automate the process of
  1343. building SWAPTEST.EXE.  To do this, enter the following at the DOS command
  1344. prompt:
  1345.  
  1346.      make -fswaptest.tc2
  1347.  
  1348. Following is a list of issues with Turbo C 2.0 command line:
  1349.  
  1350.      1.   Make sure the .CODE declaration in SWAP.ASM looks like this:
  1351.  
  1352.           IF @codesize
  1353.           .CODE   _TEXT
  1354.           ELSE
  1355.           .CODE
  1356.           ENDIF
  1357.  
  1358.      2.   With the Turbo Linker (TLINK.EXE), you must explicitly list all
  1359.           object modules, including the C startup code (c0?.obj).  In the
  1360.           Small and Medium models, you must list the startup module before
  1361.           the swap module.  For example, to create a small-model version of
  1362.           SWAPTEST.EXE, you would use this TLINK.EXE command line:
  1363.  
  1364.           tlink c:\lib\c0s swaps swaptest, swaptest, swaptest,
  1365.                c:\lib\cs.lib
  1366.  
  1367.           If you specify swaps before c:\lib\c0s, the Turbo Linker gets
  1368.           confused, and generates an executable file that will always report
  1369.           "Null Pointer Assignment" at program termination.  A null pointer
  1370.           assignment has not necessarily occurred, but the message will be
  1371.           printed anyway.
  1372.  
  1373.           With the Medium and Large models, it is OK to list the swap()
  1374.           object module first:
  1375.  
  1376.           tlink swapl c:\lib\c0l swaptest, swaptest, swaptest,
  1377.                c:\lib\cl.lib
  1378.  
  1379.           This will generate no spurious "Null Pointer Assignment" messages.
  1380.  
  1381.      3.   Unless your program directly allocates extra DOS memory blocks
  1382.           (either by calling DOS function 48 hex or by calling allocmem()),
  1383.           you can get by without using the fragmentation feature of swap()
  1384.           ("/DNoFrag").  However, the memory savings will be minimal, and
  1385.           this is not recommended.
  1386.  
  1387.  
  1388.  
  1389.  
  1390.  
  1391.  
  1392.  
  1393. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         22
  1394.  
  1395.  
  1396.  
  1397.  
  1398. 2.   Integrated Environment
  1399.  
  1400. Following is a list of issues with Turbo C 2.0 integrated environment:
  1401.  
  1402.      1.   Make sure the .CODE declaration in SWAP.ASM looks like this:
  1403.  
  1404.           IF @codesize
  1405.           .CODE   _TEXT
  1406.           ELSE
  1407.           .CODE
  1408.           ENDIF
  1409.  
  1410.      2.   In the Integrated Development Environment (IDE) of Turbo C 2.0,
  1411.           you use project files (*.PRJ) to specify the source files and
  1412.           object modules used to build an executable program.  You should
  1413.           always list the swap() object module on the first line of this
  1414.           file:
  1415.  
  1416.                swaps.obj
  1417.                swaptest.c (swap.h)
  1418.  
  1419.           This is demonstrated in the file SWAPTEST.PRJ included in the file
  1420.           TC2.ZIP.
  1421.  
  1422.      3.   Unless your program directly allocates extra DOS memory blocks
  1423.           (either by calling DOS function 48 hex or by calling allocmem()),
  1424.           you can get by without using the fragmentation feature of swap()
  1425.           ("/DNoFrag").  However, the memory savings will be minimal, and
  1426.           this is not recommended.
  1427.  
  1428.  
  1429. D.   Turbo C++ 1.0
  1430.  
  1431.      Turbo C++ 1.0 provides two ways to build an executable program:  a
  1432. command-line environment (using TCC.EXE and TLINK.EXE), and an integrated
  1433. development environment.
  1434.  
  1435.      The file TCP.ZIP, included in this distribution, contains example files
  1436. for building SWAPTEST.EXE with Turbo C++ 1.0, both command-line and
  1437. integrated environments.
  1438.  
  1439.  
  1440. 1.   Command Line
  1441.  
  1442.      You can build SWAPTEST.EXE with TCC.EXE (Turbo C++ 1.0), TASM.EXE
  1443. (Turbo Assembler 2.0), TLINK.EXE (Turbo Linker 3.0), and MAKE.EXE (Turbo
  1444. Make 3.0).  A make file called SWAPTEST.TCP is included to automate the
  1445. process of building SWAPTEST.EXE.  To do this, enter the following at the
  1446. DOS command prompt:
  1447.  
  1448.      make -fswaptest.tcp
  1449.  
  1450.  
  1451.  
  1452. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         23
  1453.  
  1454.  
  1455.  
  1456.  
  1457. Following is a list of issues with Turbo C++ 1.0 command line:
  1458.  
  1459.      1.   Make sure the .CODE declaration in SWAP.ASM looks like this:
  1460.  
  1461.           IF @codesize
  1462.           .CODE   _TEXT
  1463.           ELSE
  1464.           .CODE
  1465.           ENDIF
  1466.  
  1467.      2.   With the Turbo Linker (TLINK.EXE), you must explicitly list all
  1468.           object modules, including the C startup code (c0?.obj).  In all
  1469.           memory models in Turbo C++ 1.0, you can provide maximum memory for
  1470.           the executed program by listing the swap() object module first on
  1471.           the Turbo Link command line.  For example, to create a small-model
  1472.           version of SWAPTEST.EXE, you would use this TLINK.EXE command
  1473.           line:
  1474.  
  1475.           tlink swaps c:\lib\c0s swaptest, swaptest, swaptest,
  1476.                c:\lib\cs.lib
  1477.  
  1478.           Turbo C++ 1.0 does not exhibit the "Null Pointer Assignment"
  1479.           problems of Turbo C 2.0 listed above.
  1480.  
  1481.      3.   Unless your program directly allocates extra DOS memory blocks
  1482.           (either by calling DOS function 48 hex or by calling allocmem()),
  1483.           you can get by without using the fragmentation feature of swap()
  1484.           ("/DNoFrag").  However, the memory savings will be minimal, and
  1485.           this is not recommended.
  1486.  
  1487.      4.   If you are using Turbo C++ to compile a C++ program, you must take
  1488.           extra steps to ensure that swap() is linked into your executable
  1489.           successfully.  This is due to the type-safe linkage feature of
  1490.           Turbo C++ 1.0.  Turbo C++ 1.0 adds characters to the names of C
  1491.           functions it compiles to allow the linker to check the types of
  1492.           parameters being passed to it (swap() becomes @swap$qnuct1t1t1()).
  1493.  
  1494.           Because swap() is assembled by the Turbo Assembler, and not
  1495.           compiled by Turbo C++, you must tell the compiler not to add these
  1496.           characters to the swap() name when it is called from your program. 
  1497.           This is taken care of in the SWAP.H file where the function
  1498.           prototype of swap() is declared.  It hinges on "__cplusplus" being
  1499.           defined (as it always is when doing a C++ compile).  This follows
  1500.           the standard set with the Turbo C++ 1.0 include files.
  1501.  
  1502.  
  1503. 2.   Integrated Environment
  1504.  
  1505. Following is a list of issues with Turbo C++ 1.0 integrated environment:
  1506.  
  1507.      1.   Make sure the .CODE declaration in SWAP.ASM looks like this:
  1508.  
  1509.  
  1510.  
  1511. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         24
  1512.  
  1513.  
  1514.  
  1515.  
  1516.           IF @codesize
  1517.           .CODE   _TEXT
  1518.           ELSE
  1519.           .CODE
  1520.           ENDIF
  1521.  
  1522.           This is especially important when using the integrated environment
  1523.           of Turbo C++ 1.0.  If the .CODE directive above were "SWAP_TEXT"
  1524.           instead of "_TEXT", the swap() routine would be linked after all
  1525.           of the Turbo C++ library routines (printf(), etc.).  In large
  1526.           programs, this means that swap() would be unable to swap out large
  1527.           chunks of your executable, partially defeating its purpose.
  1528.  
  1529.           The ".CODE _TEXT" directive puts the swap() routine in the same
  1530.           segment as the Turbo C++ library routines, and if you follow the
  1531.           procedure in step 2 below, swap() will be able to swap out the
  1532.           maximum possible amount of your program.
  1533.  
  1534.      2.   In the Integrated Development Environment (IDE) of Turbo C++ 1.0,
  1535.           you use project files (*.PRJ) to specify the source files and
  1536.           object modules used to build an executable program.  These project
  1537.           files are very different than project files from Turbo C 2.0.
  1538.  
  1539.           The swap() object module should always be the first item listed in
  1540.           the project file.  Please consult the Turbo C++ 1.0 manual for
  1541.           information on creating a project file.
  1542.  
  1543.      3.   Unless your program directly allocates extra DOS memory blocks
  1544.           (either by calling DOS function 48 hex or by calling allocmem()),
  1545.           you can get by without using the fragmentation feature of swap()
  1546.           ("/DNoFrag").  However, the memory savings will be minimal, and
  1547.           this is not recommended.
  1548.  
  1549.  
  1550.  
  1551.  
  1552.  
  1553.  
  1554.  
  1555.  
  1556.  
  1557.  
  1558.  
  1559.  
  1560.  
  1561.  
  1562.  
  1563.  
  1564.  
  1565.  
  1566.  
  1567.  
  1568.  
  1569.  
  1570. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         25
  1571.  
  1572.  
  1573.  
  1574.  
  1575. VII. Revision History
  1576.  
  1577. Revision  Date      Comments
  1578. ---------------------------------------------------------------------------
  1579.  1.00     4/1/90    Initial revision.  Supported swapping to expanded memory
  1580.                     or disk.  Supported Small and Medium memory models.
  1581.  
  1582.  2.00     9/6/90    Added support for swapping to XMS extended memory. 
  1583.                     Added support for Compact, Large, and Huge memory
  1584.                     models.  Made .ASM source file configurable.
  1585.  
  1586.  2.01     9/7/90    It's always something!  SWAPTEST.LNK was missing from
  1587.                     the release .ZIP file.  SWAP.DOC did not have page
  1588.                     numbers in the table of contents.
  1589.  
  1590.  2.10     9/11/90   Added code to parse the command line into the default
  1591.                     FCBs (thanks to David E. Jenkins).  Changed /D[model]
  1592.                     definitions to allow assembly with Turbo Assembler.
  1593.  
  1594.  2.11     9/28/90   Fixed problem in SWAP.ASM (variable called cmd_pad). 
  1595.                     This prevented execution of COMMAND.COM with arguments,
  1596.                     as the pad byte (0) is interpreted by COMMAND.COM as the
  1597.                     end of the command line.  Ooops!  Also, added
  1598.                     information about using Microsoft C 6.00.
  1599.  
  1600.  3.00     10/4/90   Added full support for Microsoft C 6.00 large code
  1601.                     memory models (fragmentation support).  Added complete
  1602.                     information about compiling, assembling, and linking in
  1603.                     all supported compiler versions and memory models. 
  1604.                     Fixed error in disk restore routine--it wasn't deleting
  1605.                     the swap file after it was done.  Swap() no longer
  1606.                     supports EMS version 3.2--EMS 4.0 and above is required.
  1607.  
  1608.  
  1609.  
  1610.  
  1611.  
  1612.  
  1613.  
  1614.  
  1615.  
  1616.  
  1617.  
  1618.  
  1619.  
  1620.  
  1621.  
  1622.  
  1623.  
  1624.  
  1625.  
  1626.  
  1627.  
  1628.  
  1629. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         26
  1630.  
  1631.  
  1632.  
  1633.  
  1634. VIII. Information
  1635.  
  1636.      The original version of swap() was released as SWAP100.ZIP on April 1,
  1637. 1990.  That version supported swapping to expanded memory and to disk, and
  1638. only the Small memory model was supported.
  1639.  
  1640.      Since then, I have had many people call both to thank me (I'm blushing)
  1641. and to request enhancements.  I am grateful to these people (Norman Hamer,
  1642. William Wood, David Jenkins, et al) for helping to make this product more
  1643. useful.
  1644.  
  1645.      This version of swap(), like all previous (and future!) versions, is
  1646. hereby released into the public domain for free use by anybody and
  1647. everybody.  However, all the contents of this package still remain:
  1648.  
  1649.      Copyright (C) 1990 by Marty Del Vecchio.  All Rights Reserved.
  1650.  
  1651.      I am not requesting a donation from anybody who uses the contents of
  1652. this package.  I just ask that everybody who does use swap() realize the
  1653. amount of work that went into coding it, and appreciate the fact that I
  1654. fully commented and released the source code for free.  If you use swap() in
  1655. a commercial program, and would like it listed in this document, please
  1656. contact me to let me know.
  1657.  
  1658.      Everything in this package is provided with no warranties whatsoever,
  1659. express nor implied, for any functionality or fitness for a specific
  1660. purpose.  The author will not be held responsible for any damages whatsoever
  1661. resulting from the use of this package, and will not be held responsible if
  1662. the package does not perform.  User beware!
  1663.  
  1664. My home address is:
  1665.  
  1666.      Marty Del Vecchio
  1667.      99 Marlboro Road
  1668.      Southborough, MA  01772
  1669.  
  1670. My home phone number is:
  1671.  
  1672.      (508) 485-9718
  1673.  
  1674. My internet mail address is:
  1675.  
  1676.      marty@bsn.mceo.dg.com
  1677.  
  1678. My main bulletin board is:
  1679.  
  1680.      Channel 1 BBS
  1681.      Boston, MA
  1682.      (617) 354-8873
  1683.  
  1684.  
  1685.  
  1686.  
  1687.  
  1688. SWAP.DOC  Copyright (C) 1990 by Marty Del Vecchio                         27
  1689.  
  1690.